﻿namespace Sidvall.Serialization
{
    public static class StringExtension
    {
        #region Append

        public static string Append(this string value, string text, string separator)
        {
            if (!string.IsNullOrWhiteSpace(text))
            {
                if (!string.IsNullOrWhiteSpace(value))
                {
                    if (separator != null)
                        return value + separator + text;
                    else
                        return value + text;
                }
                else
                    return text;
            }
            return value;
        }

        #endregion
        #region Contains

        public static bool Contains(this string value, string text, System.StringComparison comparison)
        {
            int index;

            if (value == null)
                return false;
            if (text == null)
                return false;
            index = value.IndexOf(text, comparison);
            if (index != -1)
                return true;
            return false;
        }

        #endregion
        #region Equals

        public static bool Equals(this string value, string text, bool ignoreWhiteSpace, System.StringComparison comparison)
        {
            if (ignoreWhiteSpace)
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    if (string.IsNullOrWhiteSpace(text))
                        return true;
                    else
                        return false;
                }
                if (string.IsNullOrWhiteSpace(text))
                    return false;
                return value.Equals(text, comparison);
            }
            else
            {
                if (value == null)
                {
                    if (text == null)
                        return true;
                    else
                        return false;
                }
                if (text == null)
                    return false;
                return value.Equals(text, comparison);
            }
        }

        #endregion
        #region Replace

        public static string Replace(this string value, string oldValue, string newValue, System.StringComparison comparison)
        {
            if (value == null)
                return value;
            if (oldValue == null)
                return value;
            if (oldValue.Length == 0)
                return value;
            if (newValue.Equals(oldValue, false, System.StringComparison.Ordinal))
                return value;
            return ReplaceInternal(value, oldValue, newValue, comparison);
        }
        private static string ReplaceInternal(string value, string oldValue, string newValue, System.StringComparison comparison)
        {
            var sb = new System.Text.StringBuilder();
            var previousIndex = 0;
            var index = value.IndexOf(oldValue, comparison);
            while (index != -1)
            {
                sb.Append(value.Substring(previousIndex, index - previousIndex));
                sb.Append(newValue);
                index += oldValue.Length;

                previousIndex = index;
                index = value.IndexOf(oldValue, index, comparison);
            }
            sb.Append(value.Substring(previousIndex));
            return sb.ToString();
        }
        public static string Replace(this string value, string[] oldValues, string newValue, System.StringComparison comparison)
        {
            if (value == null)
                return value;
            if (oldValues == null)
                return value;
            var index = new System.Collections.Generic.HashSet<string>();
            foreach (var oldValue in oldValues)
            {
                if (oldValue == null)
                    continue;
                if (oldValue.Length == 0)
                    continue;
                if (newValue.Equals(oldValue, false, System.StringComparison.Ordinal))
                    continue;
                if (!index.Contains(oldValue))
                {
                    value = ReplaceInternal(value, oldValue, newValue, comparison);
                    index.Add(oldValue);
                }
            }
            return value;
        }

        #endregion
        #region Split

        public static string[] Split(this string value, string separator)
        {
            return Split(value, separator, System.StringSplitOptions.None);
        }
        public static string[] Split(this string value, string separator, System.StringSplitOptions options)
        {
            if (value == null)
                return null;
            return value.Split(new string[] { separator }, options);
        }

        #endregion
        #region Trim

        public static string Trim(this string value, string trimValue, System.StringComparison comparison)
        {
            if (value == null)
                return null;
            if (trimValue == null)
                return value;
            if (value.StartsWith(trimValue, comparison))
                value = value.Substring(trimValue.Length);
            if (value.EndsWith(trimValue, comparison))
                value = value.Substring(0, value.Length - trimValue.Length);
            return value;
        }

        #endregion
        #region TrimEnd

        public static string TrimEnd(this string value, string trimValue, System.StringComparison comparison)
        {
            if (value == null)
                return null;
            if (trimValue == null)
                return value;
            if (value.EndsWith(trimValue, comparison))
                value = value.Substring(0, value.Length - trimValue.Length);
            return value;
        }

        #endregion
        #region TrimStart

        public static string TrimStart(this string value, string trimValue, System.StringComparison comparison)
        {
            if (value == null)
                return null;
            if (trimValue == null)
                return value;
            if (value.StartsWith(trimValue, comparison))
                value = value.Substring(trimValue.Length);
            return value;
        }

        #endregion

        #region ToEnum

        public static T ToEnum<T>(this string value, T defaultValue) where T : struct
        {
            T? result;

            result = value.ToNullableEnum<T>();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToBoolean

        public static bool ToBoolean(this string value, bool defaultValue)
        {
            bool? result;

            result = value.ToNullableBoolean();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToChar

        public static char ToChar(this string value, char defaultValue)
        {
            char? result;

            result = value.ToNullableChar();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToDateTime

        public static System.DateTime ToDateTime(this string value, System.DateTime defaultValue)
        {
            var result = value.ToNullableDateTime();
            if (result == null)
                return defaultValue;
            return result.Value;
        }
        public static System.DateTime ToDateTime(this string value, System.DateTime defaultValue, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles)
        {
            var result = value.ToNullableDateTime(provider, styles);
            if (result == null)
                return defaultValue;
            return result.Value;
        }

        #endregion
        #region ToDateTimeOffset

        public static System.DateTimeOffset ToDateTimeOffset(this string value, System.DateTimeOffset defaultValue)
        {
            var result = value.ToNullableDateTimeOffset();
            if (result == null)
                return defaultValue;
            return result.Value;
        }
        public static System.DateTimeOffset ToDateTimeOffset(this string value, System.DateTimeOffset defaultValue, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles)
        {
            var result = value.ToNullableDateTimeOffset(provider, styles);
            if (result == null)
                return defaultValue;
            return result.Value;
        }

        #endregion
        #region ToDecimal

        public static decimal ToDecimal(this string value, decimal defaultValue)
        {
            decimal? result;

            result = value.ToNullableDecimal();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToDouble

        public static double ToDouble(this string value, double defaultValue)
        {
            double? result;

            result = value.ToNullableDouble();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToByte

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "int8")]
        public static byte ToByte(this string value, byte defaultValue)
        {
            byte? result;

            result = value.ToNullableByte();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToInt16

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "int16")]
        public static short ToInt16(this string value, short defaultValue)
        {
            short? result;

            result = value.ToNullableInt16();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToInt32

        public static int ToInt32(this string value, int defaultValue)
        {
            int? result;

            result = value.ToNullableInt32();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToInt64

        public static long ToInt64(this string value, long defaultValue)
        {
            long? result;

            result = value.ToNullableInt64();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToSingle

        public static float ToSingle(this string value, float defaultValue)
        {
            float? result;

            result = value.ToNullableSingle();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion
        #region ToTimeSpan

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "Sidvall.Serialization.StringExtension.ToNullableTimeSpan(System.String)")]
        public static System.TimeSpan ToTimeSpan(this string value, System.TimeSpan defaultValue)
        {
            var result = value.ToNullableTimeSpan();
            if (result == null)
                return defaultValue;
            return result.Value;
        }
        public static System.TimeSpan ToTimeSpan(this string value, System.TimeSpan defaultValue, System.IFormatProvider provider)
        {
            var result = value.ToNullableTimeSpan(provider);
            if (result == null)
                return defaultValue;
            return result.Value;
        }

        #endregion
        #region ToGuid

        public static System.Guid ToGuid(this string value, System.Guid defaultValue)
        {
            System.Guid? result;

            result = value.ToNullableGuid();
            if (result == null)
                return defaultValue;

            return result.Value;
        }

        #endregion

        #region ToNullableEnum

        public static T? ToNullableEnum<T>(this string value) where T : struct
        {
            T result;

            if (string.IsNullOrWhiteSpace(value))
                return null;
            if (System.Enum.TryParse<T>(value, true, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableBoolean

        public static bool? ToNullableBoolean(this string value)
        {
            bool result;

            if (string.IsNullOrWhiteSpace(value))
                return null;
            if (bool.TryParse(value, out result))
                return result;
            if ((value == "0") ||
                (value.Equals("false", System.StringComparison.OrdinalIgnoreCase)) ||
                (value.Equals("n", System.StringComparison.OrdinalIgnoreCase)) ||
                (value.Equals("no", System.StringComparison.OrdinalIgnoreCase)))
            {
                return false;
            }
            else if ((value == "1") ||
                (value.Equals("true", System.StringComparison.OrdinalIgnoreCase)) ||
                (value.Equals("y", System.StringComparison.OrdinalIgnoreCase)) ||
                (value.Equals("yes", System.StringComparison.OrdinalIgnoreCase)))
            {
                return true;
            }

            return null;
        }

        #endregion
        #region ToNullableChar

        public static char? ToNullableChar(this string value)
        {
            char result;

            if (string.IsNullOrWhiteSpace(value))
                return null;
            if (char.TryParse(value, out result))
                return result;

            return null;
        }

        #endregion
        #region ToNullableDateTime

        public static System.DateTime? ToNullableDateTime(this string value)
        {
            return ToNullableDateTime(value, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None);
        }
        public static System.DateTime? ToNullableDateTime(this string value, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles)
        {
            System.DateTime result;
            if (System.DateTime.TryParse(value, provider, styles, out result))
                return result;
            return null;
        }
        public static System.DateTime? ToNullableDateTime(this string value, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles, System.DateTimeKind kind)
        {
            System.DateTime result;
            if (System.DateTime.TryParse(value, provider, styles, out result))
                return System.DateTime.SpecifyKind(result, kind);
            return null;
        }
        public static System.DateTime? ToNullableDateTime(this string value, System.DateTimeKind kind)
        {
            return ToNullableDateTime(value, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, kind);
        }

        public static System.DateTime? ToNullableDateTime(this string value, string format)
        {
            return ToNullableDateTime(value, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, format);
        }
        public static System.DateTime? ToNullableDateTime(this string value, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles, string format)
        {
            System.DateTime result;
            if (System.DateTime.TryParseExact(value, format, provider, styles, out result))
                return result;
            return null;
        }
        public static System.DateTime? ToNullableDateTime(this string value, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles, System.DateTimeKind kind, string format)
        {
            System.DateTime result;
            if (System.DateTime.TryParseExact(value, format, provider, styles, out result))
                return System.DateTime.SpecifyKind(result, kind);
            return null;
        }

        #endregion
        #region ToNullableDateTimeOffset

        public static System.DateTimeOffset? ToNullableDateTimeOffset(this string value)
        {
            return ToNullableDateTimeOffset(value, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None);
        }
        public static System.DateTimeOffset? ToNullableDateTimeOffset(this string value, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles)
        {
            System.DateTimeOffset result;
            if (System.DateTimeOffset.TryParse(value, provider, styles, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableDecimal

        public static decimal? ToNullableDecimal(this string value)
        {
            return ToNullableDecimal(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static decimal? ToNullableDecimal(this string value, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            decimal result;
            if (decimal.TryParse(value, style, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableDouble

        public static double? ToNullableDouble(this string value)
        {
            return ToNullableDouble(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static double? ToNullableDouble(this string value, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            double result;
            if (double.TryParse(value, style, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableByte

        public static byte? ToNullableByte(this string value)
        {
            return ToNullableByte(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static byte? ToNullableByte(this string value, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            byte result;
            if (byte.TryParse(value, style, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableInt16

        public static short? ToNullableInt16(this string value)
        {
            return ToNullableInt16(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static short? ToNullableInt16(this string value, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            short result;
            if (short.TryParse(value, style, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableInt32

        public static int? ToNullableInt32(this string value)
        {
            return ToNullableInt32(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static int? ToNullableInt32(this string value, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            int result;
            if (int.TryParse(value, style, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableInt64

        public static long? ToNullableInt64(this string value)
        {
            return ToNullableInt64(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static long? ToNullableInt64(this string value, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            long result;
            if (long.TryParse(value, style, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableSingle

        public static float? ToNullableSingle(this string value)
        {
            return ToNullableSingle(value, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static float? ToNullableSingle(this string value, System.Globalization.NumberStyles style, System.IFormatProvider provider)
        {
            float result;
            if (float.TryParse(value, style, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableTimeSpan

        public static System.TimeSpan? ToNullableTimeSpan(this string value)
        {
            return ToNullableTimeSpan(value, System.Globalization.CultureInfo.InvariantCulture);
        }
        public static System.TimeSpan? ToNullableTimeSpan(this string value, System.IFormatProvider provider)
        {
            System.TimeSpan result;
            if (System.TimeSpan.TryParse(value, provider, out result))
                return result;
            return null;
        }

        #endregion
        #region ToNullableGuid

        public static System.Guid? ToNullableGuid(this string value)
        {
            System.Guid result;

            if (System.Guid.TryParse(value, out result))
                return result;
            return null;
        }

        #endregion
    }
}
